package com.sinux.generality.basesupport.utils.query.query;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sinux.generality.basesupport.utils.query.OConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;

import java.beans.PropertyDescriptor;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;


@Slf4j
public class QueryGenerator {

	private static final String STAR = "*";
	private static final String COMMA = ",";
	private static final String NOT_EQUAL = "!";

	/**排序列*/
	private static final String ORDER_COLUMN = "column";
	/**排序方式*/
	private static final String ORDER_TYPE = "order";
	private static final String ORDER_TYPE_ASC = "ASC";

	/**时间格式化 */
	private static final ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();

	private static SimpleDateFormat getTime(){
		SimpleDateFormat time = local.get();
		if(time == null){
			time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			local.set(time);
		}
		return time;
	}

	/**
	 * 获取查询条件构造器QueryWrapper实例 通用查询条件已被封装完成
	 * @param searchObj 查询实体
	 * @param parameterMap request.getParameterMap()
	 * @return QueryWrapper实例
	 */
	public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap){
		long start = System.currentTimeMillis();
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
		installMyBatisPlus(queryWrapper, searchObj, parameterMap);
		System.out.println("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
//		log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
		return queryWrapper;
	}

	/**
	 * 组装Mybatis Plus 查询条件
	 *
	 * <p>使用此方法 需要有如下几点注意:   
	 * <br>1.使用QueryWrapper 而非LambdaQueryWrapper;
	 * <br>2.实例化QueryWrapper时不可将实体传入参数   
	 * <br>错误示例:如QueryWrapper<Demo> queryWrapper = new QueryWrapper<Demo>(Demo);
	 * <br>正确示例:QueryWrapper<Demo> queryWrapper = new QueryWrapper<Demo>();
	 * <br>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例
	 */
	public static void installMyBatisPlus(QueryWrapper<?> queryWrapper,Object searchObj,Map<String, String[]> parameterMap) {
		/*
		 * 注意:权限查询由前端配置数据规则 当一个人有多个所属部门时候 可以在规则配置包含条件 orgCode 包含 #{sys_org_code}
		但是不支持在自定义SQL中写orgCode in #{sys_org_code}
		当一个人只有一个部门 就直接配置等于条件: orgCode 等于 #{sys_org_code} 或者配置自定义SQL: orgCode = '#{sys_org_code}'
		*/
		//区间条件组装 模糊查询 高级查询组装 简单排序 权限查询
		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(searchObj);
		String name;
		for (int i = 0; i < origDescriptors.length; i++) {
			name = origDescriptors[i].getName();
			try {
				if (judgedIsUselessField(name)|| !PropertyUtils.isReadable(searchObj, name)) {
					continue;
				}
				//判断单值  参数带不同标识字符串 走不同的查询
				//TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效
				Object value = PropertyUtils.getSimpleProperty(searchObj, name);
				if (null != value) {
					//根据参数值带什么关键字符串判断走什么类型的查询
					QueryRuleEnum rule = convert2Rule(value);
					value = replaceValue(rule,value);
					addEasyQuery(queryWrapper, name, rule, value);
				}
			} catch (Exception e) {
				e.printStackTrace();
				System.err.println(e.getMessage());
			}
		}
		// 排序逻辑 处理
		doMultiFieldsOrder(queryWrapper, parameterMap);
	}

	public static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
		String column=null,order=null;
		if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
			column = parameterMap.get(ORDER_COLUMN)[0];
		}
		if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) {
			order = parameterMap.get(ORDER_TYPE)[0];
		}
		System.out.println("排序规则>>列:"+column+",排序方式:"+order);
//		log.debug("排序规则>>列:"+column+",排序方式:"+order);
		if (OConvertUtils.isNotEmpty(column) && OConvertUtils.isNotEmpty(order)) {
			if (order.toUpperCase().indexOf(ORDER_TYPE_ASC)>=0) {
				queryWrapper.orderByAsc(OConvertUtils.camelToUnderline(column));
			} else {
				queryWrapper.orderByDesc(OConvertUtils.camelToUnderline(column));
			}
		}
	}

	/**
	 * 根据所传的值 转化成对应的比较方式
	 * 支持><= like in !
	 * @param value
	 * @return
	 */
	public static QueryRuleEnum convert2Rule(Object value) {
				// 避免空数据
				if (value == null) {
					return null;
				}
				String val = (value + "").toString().trim();
				if (val.length() == 0) {
					return null;
				}
				QueryRuleEnum rule =null;
				// step 2 .>= =<
				if (rule == null && val.length() >= 2) {
					rule = QueryRuleEnum.getByValue(val.substring(0, 2));
				}
				// step 1 .> <
				if (rule == null && val.length() >= 1) {
					rule = QueryRuleEnum.getByValue(val.substring(0, 1));
				}

				// step 3 like
				if (rule == null && val.contains(STAR)) {
					if (val.startsWith(STAR) && val.endsWith(STAR)) {
						rule = QueryRuleEnum.LIKE;
					} else if (val.startsWith(STAR)) {
						rule = QueryRuleEnum.LEFT_LIKE;
					} else if(val.endsWith(STAR)){
						rule = QueryRuleEnum.RIGHT_LIKE;
					}
				}
				// step 4 in
				if (rule == null && val.contains(COMMA)) {
					//TODO in 查询这里应该有个bug  如果一字段本身就是多选 此时用in查询 未必能查询出来
					rule = QueryRuleEnum.IN;
		}
		// step 5 != 
		if(rule == null && val.startsWith(NOT_EQUAL)){
			rule = QueryRuleEnum.NE;
		}
		return rule != null ? rule : QueryRuleEnum.EQ;
	}

	/**
	 * 替换掉关键字字符
	 *
	 * @param rule
	 * @param value
	 * @return
	 */
	public static Object replaceValue(QueryRuleEnum rule, Object value) {
		if (rule == null) {
			return null;
		}
		if (! (value instanceof String)){
			return value;
		}
		String val = (value + "").toString().trim();
		if (rule == QueryRuleEnum.LIKE) {
			value = val.substring(1, val.length() - 1);
		} else if (rule == QueryRuleEnum.LEFT_LIKE || rule == QueryRuleEnum.NE) {
			value = val.substring(1);
		} else if (rule == QueryRuleEnum.RIGHT_LIKE) {
			value = val.substring(0, val.length() - 1);
		} else if (rule == QueryRuleEnum.IN) {
			value = val.split(",");
		} else {
			value = val.replace(rule.getValue(),"");
		}
		return value;
	}



	/**
	 * 获取日期类型的值
	 * @param value
	 * @param rule
	 * @return
	 * @throws ParseException
	 */
	private static Date getDateQueryByRule(String value,QueryRuleEnum rule) throws ParseException {
		Date date = null;
		if(value.length()==10) {
			if(rule==QueryRuleEnum.GE) {
				//比较大于
				date = getTime().parse(value + " 00:00:00");
			}else if(rule==QueryRuleEnum.LE) {
				//比较小于
				date = getTime().parse(value + " 23:59:59");
			}
			//TODO 日期类型比较特殊 可能oracle下不一定好使
		}
		if(date==null) {
			date = getTime().parse(value);
		}
		return date;
	}

	/**
	 * 根据规则走不同的查询
	 * @param queryWrapper QueryWrapper
	 * @param name         字段名字
	 * @param rule         查询规则
	 * @param value        查询条件值
	 */
	private static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
		if (value == null || rule == null) {
			return;
		}
		name = OConvertUtils.camelToUnderline(name);
		System.out.println("--查询规则-->"+name+" "+rule.getValue()+" "+value);
//		log.info();
		switch (rule) {
			case GT:
				queryWrapper.gt(name, value);
				break;
			case GE:
				queryWrapper.ge(name, value);
				break;
			case LT:
				queryWrapper.lt(name, value);
				break;
			case LE:
				queryWrapper.le(name, value);
				break;
			case EQ:
				queryWrapper.eq(name, value);
				break;
			case NE:
				queryWrapper.ne(name, value);
				break;
			case IN:
				if(value instanceof String) {
					queryWrapper.in(name, (Object[])value.toString().split(","));
				}else if(value instanceof String[]) {
					queryWrapper.in(name, (Object[]) value);
				}else {
					queryWrapper.in(name, value);
				}
				break;
			case LIKE:
				queryWrapper.like(name, value);
				break;
			case LEFT_LIKE:
				queryWrapper.likeLeft(name, value);
				break;
			case RIGHT_LIKE:
				queryWrapper.likeRight(name, value);
				break;
			default:
				System.out.println("--查询规则未匹配到---");
				break;
		}
	}
	/**
	 *
	 * @param name
	 * @return
	 */
	private static boolean judgedIsUselessField(String name) {
		return "class".equals(name) || "ids".equals(name)
				|| "page".equals(name) || "rows".equals(name)
				|| "sort".equals(name) || "order".equals(name);
	}

}
